﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
using System.Timers;
using System.IO;
using System.Text.RegularExpressions;
using System.Security.Permissions;
using System.Reflection;
using System.Windows.Media;
using System.Windows.Forms;

using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Inventory;
using Styx.CommonBot.POI;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

using UltraFTW.data.libs;
using UltraFTW.data.libs.util;

namespace UltraFTW.data.libs.core
{
    static class FTWCoreStatus
    {
        public static List<String[]> ListMyAuras()
        {
            return ListAuras(StyxWoW.Me);
        }

        public static List<String[]> ListTargetAuras()
        {
            return ListAuras(StyxWoW.Me.CurrentTarget);
        }

        public static List<String[]> ListAuras(WoWUnit target)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                List<String[]> aura_list = new List<String[]>();
                if (target != null)
                {
                    foreach (WoWAura aura in target.GetAllAuras())
                    {
                        String[] arr = { "", "", "" };
                        arr[0] = aura.Name;
                        arr[1] = (aura.StackCount == 0 ? "" : aura.StackCount.ToString());
                        arr[2] = (aura.TimeLeft.TotalSeconds == 0 ? "" : string.Format("{0:0.00}", aura.TimeLeft.TotalSeconds));
                        aura_list.Add(arr);
                    }
                }
                return aura_list;
            }
        }

        public static List<String[]> ListCooldowns()
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                WoWSpell spell = null;
                List<String> keys = FTWProps.spellWasLastCast.Keys.ToList();
                keys.Sort();

                List<String[]> cooldowns = new List<String[]>();
                foreach (String key in keys)
                {
                    String[] arr = new String[4];
                    arr[0] = key;
                    FakeCooldown fc = null;
                    if (FTWProps.fakecooldowns.ContainsKey(key))
                    {
                        fc = FTWProps.fakecooldowns[key];
                        arr[1] = fc.SpellID.ToString();
                    }
                    else
                    {
                        spell = SpellManager.Spells[key];
                        arr[1] = spell.Id.ToString();
                    }
                    arr[2] = string.Format("{0:hhmmss}", FTWProps.spellWasLastCast[key]);
                    double cooldownremaining = 0;
                    if (fc != null)
                        cooldownremaining = FTWProps.spellWasLastCast[key].AddSeconds(fc.Cooldown).Subtract(DateTime.Now).TotalSeconds;
                    else
                        cooldownremaining = spell.CooldownTimeLeft.TotalSeconds;
                    arr[3] = (cooldownremaining <= 0 ? "" : string.Format("{0:0.00}", cooldownremaining));
                    cooldowns.Add(arr);
                }
                return cooldowns;
            }
        }

        public static bool OnCooldown(FTWAction act_obj, Dictionary<string, string> vals, Dictionary<string, bool> flags) { return OnCooldown(act_obj.param); }

        public static bool OnCooldown(string spellname, double seconds = -1)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                FTWRetCode ret_val = new FTWRetCode();
                ret_val.flags = new Dictionary<string, bool>() { { "WowCooldown", false }, { "FTWCooldown", false }, { "RecentCooldown", false }, { "ElapsedCooldown", false } };
                ret_val.num_flags = new Dictionary<string, double>() { { "ElapsedTime", -1.0 } };
                ret_val.err_msgs = new Dictionary<string, string>();

                Color ds = Colors.Magenta;
                WoWSpell spell = null;

                if (FTWProps.fakecooldowns.ContainsKey(spellname))
                    spell = WoWSpell.FromId(FTWProps.fakecooldowns[spellname].SpellID);
                else if (SpellManager.Spells.ContainsKey(spellname))
                    spell = SpellManager.Spells[spellname];
                else
                {
                    ret_val.failed = true;
                    ret_val.err_msgs.Add("CODE", "Invalid Spell");
                }

                if (!ret_val.failed)
                {
                    if (FTWProps.spellWasLastCast.ContainsKey(spellname))
                    {
                        TimeSpan t_delta = DateTime.Now - FTWProps.spellWasLastCast[spellname];

                        double elapsedtime = t_delta.Hours * 3600 + t_delta.Minutes * 60 + t_delta.Seconds;
                        ret_val.num_flags["ElapsedTime"] = elapsedtime;

                        uint cd = Math.Min(spell.CastTime, 1500);
                        ret_val.flags["RecentCooldown"] = ((FTWProps.lastspellcastname == spellname) && (DateTime.Now - FTWProps.lastspellcasttime).TotalMilliseconds < cd);

                        if (seconds > 0)
                            ret_val.flags["ElapsedCooldown"] = (elapsedtime < seconds);

                        if (FTWProps.fakecooldowns.ContainsKey(spellname))
                            ret_val.flags["FTWCooldown"] = (elapsedtime < FTWProps.fakecooldowns[spellname].Cooldown);

                    }
                    ret_val.flags["WowCooldown"] = spell.Cooldown;

                    ret_val.status = (ret_val.flags["FTWCooldown"] || ret_val.flags["RecentCooldown"] || ret_val.flags["WowCooldown"] || ret_val.flags["ElapsedCooldown"]);
                }

                if (FTWLogger.debug_mode)
                    FTWLogger.log(ds, "Cooldown report: Failed={0} Status={1} ElapsedTime={2} WowCooldown={3} FTWCooldown={4} RecentCooldown={5} ElapsedCooldown={6}", ret_val.failed, ret_val.status, ret_val.num_flags["ElapsedTime"], ret_val.flags["WowCooldown"], ret_val.flags["FTWCooldown"], ret_val.flags["RecentCooldown"], ret_val.flags["ElapsedCooldown"]);

                return ret_val.status;
            }
        }
        
        public static void SaveCooldown(string spellname)
        {
            // Note the last time the spell was cast or action was taken, for the 'fake cooldowns.'
            FTWProps.spellWasLastCast[spellname] = DateTime.Now;
            FTWProps.lastspellcastname = spellname;
            FTWProps.lastspellcasttime = DateTime.Now;
        }
        
        public static bool OnPetCooldown(string spellname)
        {
            string fnname = "FTWCore.OnPetCooldown";
            MyTimer.Start(fnname);
            bool retval = false;
            WoWPetSpell spell = null;
            foreach (WoWPetSpell sp in StyxWoW.Me.PetSpells)
            {
                if (sp.Spell != null && sp.Spell.Name == spellname)
                {
                    spell = sp;
                    break;
                }
            }
            if (spell == null)
            {
                retval = false;
            }
            else if (spell.Cooldown)
            {
                retval = true;
            }
            else if (!FTWProps.spellWasLastCast.ContainsKey(spellname))
            {
                retval = false;
            }
            else
            {
                int elapsedtime = (DateTime.Now - FTWProps.spellWasLastCast[spellname]).Seconds;
                if (FTWProps.fakePetCooldownTimes.ContainsKey(spellname) &&
                   (elapsedtime < FTWProps.fakePetCooldownTimes[spellname]))
                    retval = true;
            }
            MyTimer.Stop(fnname);
            return retval;
        }

        public static bool On_DumpAuras(FTWAction act_obj, Dictionary<string, string> vals, Dictionary<string, bool> flags) { return On_DumpAuras(act_obj.target); }

        public static bool On_DumpAuras(WoWUnit target)
        {
            FTWLogger.debug(Colors.PaleVioletRed, "DUMPAURAS: {0} auras:", target.SafeName());
            foreach (WoWAura aura in target.Auras.Values)
                FTWLogger.debug(Colors.PaleVioletRed, "    {0} {1} {2} ms", aura.Name, aura.StackCount, aura.TimeLeft.TotalMilliseconds);
            return false;
        }

        public static bool On_DumpParty(FTWAction act_obj, Dictionary<string, string> vals, Dictionary<string, bool> flags) { return On_DumpParty(); }

        public static bool On_DumpParty()
        {
            FTWLogger.debug(Colors.Yellow, "{0} close party members:", FTWProps.closePeople.Count);
            foreach (WoWPlayer p in FTWProps.closePeople)
                FTWLogger.debug(Colors.Yellow, "    {0,-16} {1:00.0} {2:000.0}% ({3:000000} total health)", p.SafeName(), p.Distance, p.HealthPercent, p.MaxHealth);
            FTWLogger.debug(Colors.Yellow, "Tank is {0}", FTWProps.tank == null ? "<none>" : FTWProps.tank.SafeName());
            FTWLogger.debug(Colors.Yellow, "Healer is {0}", FTWProps.healer == null ? "<none>" : FTWProps.healer.SafeName());
            return false;
        }

        public static int StunCount(WoWPoint loc)
        {
            string fnname = "FTWCore.StunCount";
            MyTimer.Start(fnname);
            int cnt = (from u in FTWProps.adds
                       where u.IsCrowdControlled()
                       where u.Location.Distance(loc) < 8
                       select u).Count();
            MyTimer.Stop(fnname);
            return cnt;
        }

        public static bool HasTotem(String totemname)
        {
            foreach (WoWTotemInfo x in StyxWoW.Me.Totems)
            {
                if (x == null)
                    continue;
                if (x.WoWTotem == WoWTotem.None)
                    continue;
                if (x.Name == totemname)
                    return true;
            }
            return false;
        }

        public static int TotemCount()
        {
            int ctr = 0;
            foreach (WoWTotemInfo x in StyxWoW.Me.Totems)
            {
                if (x == null)
                    continue;
                if (x.WoWTotem == WoWTotem.None)
                    continue;
                ctr += 1;
            }
            return ctr;
        }
    }
}
